/**
 * 如何中断I/O阻塞的任务(二)
 *
 * @author fireway
 * @since 2019年 01月 28日 星期一 07:18:16 CST
 */
package concurrency;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

class NIOBlocked implements Runnable {
    private SocketChannel mSC;

    public NIOBlocked(SocketChannel sc) {
        mSC = sc;
    }

    @Override
    public void run() {
        System.out.println("Waiting for read() in " + this);
        try {
            mSC.read(ByteBuffer.allocate(1));
        } catch(ClosedByInterruptException e) {
            System.out.println(this + " occur ClosedByInterruptException");
        } catch(AsynchronousCloseException e) {
            System.out.println(this + " occur AsynchronousCloseException");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Exiting NIOBlocked.run() " + this);
    }
}

public class NIOInterruption {
    public static void main(String[] args) {
        try {
            ExecutorService exec = Executors.newCachedThreadPool();
            ServerSocket server = new ServerSocket(8080);
            InetSocketAddress isa = new InetSocketAddress("localhost", 8080);
            SocketChannel sc1 = SocketChannel.open(isa);
            SocketChannel sc2 = SocketChannel.open(isa);
            
            NIOBlocked nb1 = new NIOBlocked(sc1);
            NIOBlocked nb2 = new NIOBlocked(sc2);           
            System.out.println(nb1);
            System.out.println(nb2);
            
            Future<?> f = exec.submit(nb1);
            exec.execute(nb2);
            exec.shutdown();
            
            TimeUnit.SECONDS.sleep(1);
            
            // Produce an interrupt via cancel:
            System.out.println(nb1 + " cancel true");
            f.cancel(true);
            
            TimeUnit.SECONDS.sleep(1);
            
            // Release the block by closing the channel:
            System.out.println(nb2 + " close this stream");
            sc2.close();   
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void main2(String[] args) {       
        try {
            ExecutorService exec = Executors.newCachedThreadPool();
            ServerSocket server = new ServerSocket(8080);
            InetSocketAddress isa = new InetSocketAddress("localhost", 8080);
            SocketChannel sc1 = SocketChannel.open(isa);
            SocketChannel sc2 = SocketChannel.open(isa);
            
            NIOBlocked nb1 = new NIOBlocked(sc1);
            NIOBlocked nb2 = new NIOBlocked(sc2);           
            System.out.println(nb1);
            System.out.println(nb2);
            
            Future<?> f = exec.submit(nb1);
            exec.execute(nb2);
            // exec.shutdown();
            
            TimeUnit.SECONDS.sleep(1);
                 
            System.out.println("Attempts to stop all actively executing tasks, halts the processing of waiting tasks");
            List<Runnable> list = exec.shutdownNow();
            System.out.println("list of tasks that never commenced execution: " + list);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
